package android_testsuite.mytest.rsa;

import android.content.Context;
import android.os.Environment;
import android.util.Base64;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import android_testsuite.R;

/**
 * @author Ren Hui
 * @since 1.0.1.058
 */
public class RsaDecoder {
    private static final String DECODE_ALGO = "RSA";
    private static final int MAX_DECRYPT_BLOCK_BASE64 = 172;
    private Context mContext;
    private static final String PUBLIC_KEY =
            "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo3AWzkeBBfdPG9pTZ4cWp32Fg" +
            "+yTuc+KtTviRpfhF1oXszUHv0xlTG0aFnNwwGipe7Y7x0oIibQxwYBKSFKMr7uHi" +
            "xY1hBePvONAwMO1JA99JUY+FKVbx3sCD4Mz8//Iztt2nto16Qa71PN6fHjpldCII" +
            "yflsssFtuiWlBZJaDwIDAQAB";
    private String mContent;
    private PublicKey mPublicKey = null;

    public RsaDecoder(Context context) {
        super();
        mContext = context;
        //TODO [Ren Hui]：此解密方法主要是验证之前的加密是否正确，如果需要，给mContent赋值。
        mContent = "e4v3ra0zwrRFiEFBp5Fq4nXNKlQtWzUx6aP63KftH7wDTk35qHEjmnFlvdsEb60DTKvlkQ9UE+BPllp7myMi7ftVduUUIkychW5rqI66XJR8ToObGWtOJYdI6qsYYOZzPbm+0LqHAhoiSpazHc+1F9sy6gbIgUougBg9mRNKPrg=" +
                "WZEZuGgXp8diPAa1Lr/rl2ht0hkehkYLPtEi/+DAYHt30wc4pim7U505O//acuutAdu3I8dSVSDiv2i9qdKvjpxMBQl5gprNXnLYa+kR1Uyz18OaYPnV+fhmgp7CjPX8ifzzGMJYmILoZfIEgJDw38W3nkSRLf7p01LWOosFYqo=" +
                "XnbHy0nYAvqgvdgQ1vjqwVdw/fPyqbezcvzYRx21wEd4F1D7KeG1vd3Y/swf9fLbUgMMor6t7J+EYwe1rX0c3+jfGNtlatbDwvk4t/psf7GOkYgJ+FP/GhuUgoR6P/rAD+8EI24SxQtwVuWtmBKwUADIX264CnSU35BQQlv+lkI=" +
                "X8J8s5cbaphV1nrMB+RbLLIqMBwOytr0DY3lLzMZVL8VQMewu1NzjfQEI2ztLqwgl+A84nHmfjke9fg3a0VVdLYzmDRhZgO2PXtzcAN7X6MqLqyt58j7KGouvfmVPgOTSxV0677VvfFBmhFIyBa4YHSIuOSCRzPEQAsINqIdGjw=" +
                "QXBmtBvdlCHnmwjfxOuUCvmvi/xzO4fC2ryndrplfhy/m2ZN+cFt4DXS1CH8hFGIZh/7WP5SAJFZhM4TKQ0rNjSrh2i0lTTITZKYcBYzjezjMIJ/LMBtjDiaxoaawUpyVDZivxJurJ6azfc+2q5Bt5j4L4vbv8RT67LmO5fvO4I=" +
                "Rbm5OUxvBfYaJx+iQcpLsQfx6q9LLL+0KrKa8MK1qo2oBsekuqaf2WaTuOGNlQYVo9LwyR6Nctf3sZwyYPEkWi7DND0ixPQ4raE9uREyfBtXTLU7bh1poh+nCbMTivTtHHSeI2KoUugPBMp5p/WTleEFQQqq0qxVzWJdt8wWd+I=" +
                "BPyHVg8DTYnQvpLN9lr+a5i0zpav1Xh0makmvE4ooZqYxy2bPpY5+XF8JQ+BIJHP3xSak82wOc+vBbyguBwIaBq4u+LZbodq6vIjzCFib47YJEAEdhgfPkbvfMieAxCahh1u4u4/3MGfYLcb3cmh1lz9WlkWl6gSFEKgUIBgAyI=" +
                "Y5bUZgXoM9VvOdIEYz0aSqpy6VmrJ54F+KVGBQ03bwUcpwzPWzySQFG+ptFw/dct/pXY753rhByq4/fn/+mc7XdIS1M36GZPRnz5wZlon8FnqBP00iD0ExfG1oGwqSv7Fdpxh37j9laF8AmF0L0ZKi3+3uANr8lCP8EAmV+7MVQ=" +
                "gJxrksWH2Kxw8XwGITOf1SlHklT1/Xng4f/aRxKoxbhrqMMSQ3SRvXtoBeLdnqD+kocyX9serQ1uo/DcFKPrSrRFZH69mhoQ77+9707RhlN2QgbSgeBd3H8kBeZK2SW8H05KaVfPthoArsNdgcto8UuGO72mhSvvvE/NyTVlbzk=" +
                "WFY7WV5atyRqoMqzBWm8rwEophpNP7NCU2fO9LqK9BAgYNvi6Vf0zAC4JQ/DlgwpCG4I6Yqbg5cjwfz9jVMYmXe8E6AzIIIThzVS+uTLuU1REVlYYiXSJa6wXzDw3f6jOMCiE11AZPsSoyaNNw2KG4oXeK+Jifnr0BYn8ByV5oU=";
        if (!initPublicKey()) {
            throw new NullPointerException("Public key is null");
        }
    }

    public String decodeBase64() {
        String result = "";
        if (mContent == null || mContent.equals("")) {
            String err = mContext.getResources().getString(R.string.rsa_decrypt_tip);
            return err;
        }

        try {
            byte data[] = mContent.getBytes();
            result = decodeBase64(data);
            File file = new File(Environment.getExternalStorageDirectory().getPath() + "/DecryptResult.txt");
            file.createNewFile();
            FileOutputStream out = new FileOutputStream(file);
            out.write(result.getBytes());
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    private String decodeBase64(byte[] data) {
        int offset = 0;
        byte[] cache;
        String deCode = "";

        try {
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, this.mPublicKey);
            while (offset < data.length) {
                cache = Base64.decode(data, offset, MAX_DECRYPT_BLOCK_BASE64, Base64.NO_WRAP);
                deCode += new String(cipher.doFinal(cache));
                offset += MAX_DECRYPT_BLOCK_BASE64;
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        Log.d("RsaDecoder", deCode);
        return deCode;
    }

    private boolean initPublicKey() {
        boolean status;
        byte[] decodeKey = Base64.decode(PUBLIC_KEY, Base64.NO_WRAP);
        X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodeKey);

        try {
            KeyFactory keyFactory = KeyFactory.getInstance(DECODE_ALGO);
            this.mPublicKey = keyFactory.generatePublic(x509);
            status = true;
        } catch (NoSuchAlgorithmException e) {
            status = false;
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            status = false;
            e.printStackTrace();
        }
        return status;
    }
}
